//
// Created by lenovo on 2022/3/10.
//

#include "SignalHandler.h"
#include <vector>
#include <mutex>
#include "Logging.h"
using namespace std;

namespace AnrChecker {
    struct sigaction mOldAction;
    static bool isInstalledHandler = false;
    static vector<SignalHandler *> *mHandlerStack = nullptr;
    static mutex mHandleStackMutex;

    bool SignalHandler::registerHandlerLocked() {
        if (isInstalledHandler) {
            return false;
        }
        if (sigaction(TARGET_SIGNAL, nullptr, &mOldAction) == -1) {
            return false;
        }
        struct sigaction act{};
        act.sa_sigaction = signalHandler;
        act.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART;

        if (sigaction(TARGET_SIGNAL, &act, nullptr) == -1) {
            return false;
        }
        isInstalledHandler = true;
        return true;
    }

    bool SignalHandler::restoreHandlerLocked() {
        if (!isInstalledHandler) {
            return false;
        }
        if (sigaction(TARGET_SIGNAL, &mOldAction, nullptr) == -1) {
            struct sigaction act{};
            memset(&act, 0, sizeof(act));
            sigemptyset(&act.sa_mask);
            act.sa_handler = SIG_DFL;
            act.sa_flags = SA_RESTART;
            sigaction(TARGET_SIGNAL, &act, nullptr);
        }
        isInstalledHandler = false;
        return true;
    }

    void SignalHandler::signalHandler(int signal, siginfo_t *info, void *uc) {
        unique_lock<mutex> lock(mHandleStackMutex);
        for (auto it = mHandlerStack->rbegin(); it != mHandlerStack->rend(); ++it) {
            (*it)->onReceiving(signal, info, uc);
        }
        lock.unlock();
    }

    SignalHandler::SignalHandler() {
        lock_guard<mutex> lock(mHandleStackMutex);
        if (!isInstalledHandler) {
            mHandlerStack = new vector<SignalHandler *>;
        }
        ALOGI("===================SignalHandler==================");
        registerHandlerLocked();
        mHandlerStack->push_back(this);
    }

    SignalHandler::~SignalHandler() {
        lock_guard<mutex> lock(mHandleStackMutex);
        auto it = find(mHandlerStack->begin(), mHandlerStack->end(), this);
        mHandlerStack->erase(it);
        if (mHandlerStack->empty()) {
            delete mHandlerStack;
            mHandlerStack = nullptr;
            restoreHandlerLocked();
        }
    }
}

